// Lissajous generates GIF animations of random Lissajous figures.
package main

import (
	"fmt"
	"image"
	"image/color"
	"image/gif"
	"io"
	"math"
	"math/rand"
	"os"
	"strconv"
)

//!-main
// Packages not needed by version in book.
import (
	"log"
	"net/http"
	"time"
)

//!+main

var palette = []color.Color{color.White, color.Black}

const (
	whiteIndex = 0 // first color in palette
	blackIndex = 1 // next color in palette
)

func main() {
	//!-main
	// The sequence of images is deterministic unless we seed
	// the pseudo-random number generator using the current time.
	// Thanks to Randall McPherson for pointing out the omission.
	args := map[string]float64{ // 默认参数
		"cycles":  5,     // number of complete x oscillator revolutions
		"res":     0.001, // angular resolution
		"size":    100,   // image canvas covers [-size..+size]
		"nframes": 64,    // number of animation frames
		"delay":   8,     // delay between frames in 10ms units
	}

	rand.Seed(time.Now().UTC().UnixNano())

	if len(os.Args) > 1 && os.Args[1] == "web" {
		//!+http
		handler := func(w http.ResponseWriter, r *http.Request) {
			r.ParseForm()                // 解析请求参数
			for arg_name := range args { // 遍历所有参数名
				if len(r.Form[arg_name]) > 0 { // 请求中包含该参数，提取参数值
					arg_value, err := strconv.ParseFloat(r.Form[arg_name][0], 64)
					if err != nil {
						fmt.Printf("[ERROR] while parse argument %s : %v\n", arg_name, err)
						return
					}
					args[arg_name] = arg_value // 更新参数值
				}
			}
			lissajous(w, args)
		}
		http.HandleFunc("/", handler)
		//!-http
		url := "localhost:8080"
		fmt.Printf("Start listen server %s ...", url)
		log.Fatal(http.ListenAndServe(url, nil))
		return
	}
	//!+main
	lissajous(os.Stdout, args)
}

func lissajous(out io.Writer, args map[string]float64) {
	// 提取参数，方便计算
	cycles := args["cycles"]
	res := args["res"]
	size := args["size"]
	nframes := int(args["nframes"])
	delay := int(args["delay"])

	freq := rand.Float64() * 3.0 // relative frequency of y oscillator
	anim := gif.GIF{LoopCount: nframes}
	phase := 0.0 // phase difference
	for i := 0; i < nframes; i++ {
		rect := image.Rect(0, 0, int(2*size+1), int(2*size+1))
		img := image.NewPaletted(rect, palette)
		for t := 0.0; t < float64(cycles)*2*math.Pi; t += res {
			x := math.Sin(t)
			y := math.Sin(t*freq + phase)
			img.SetColorIndex(int(size+x*size+0.5), int(size+y*size+0.5),
				blackIndex)
		}
		phase += 0.1
		anim.Delay = append(anim.Delay, delay)
		anim.Image = append(anim.Image, img)
	}
	gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
}

// 运行：go run ex1.12.go web
// 在浏览器中输入：http://localhost:8080/?cycles=20&res=0.01&size=300&nframes=500&delay=10
// 查看效果
